package com.pt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pt.common.constant.TorrentConstant;
import com.pt.common.util.BencodeUtil;
import com.pt.common.util.FileUtil;
import com.pt.dto.request.TorrentUploadRequest;
import com.pt.entity.Torrent;
import com.pt.entity.User;
import com.pt.entity.Peer;
import com.pt.mapper.TorrentMapper;
import com.pt.service.TorrentService;
import com.pt.service.UserService;
import com.pt.service.PeerService;
import com.pt.service.NotificationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.nio.charset.StandardCharsets;

@Service
@Slf4j
public class TorrentServiceImpl extends ServiceImpl<TorrentMapper, Torrent> implements TorrentService {
    
    private final UserService userService;
    private final PeerService peerService;
    private final NotificationService notificationService;

    public TorrentServiceImpl(UserService userService, @Lazy PeerService peerService, NotificationService notificationService) {
        this.userService = userService;
        this.peerService = peerService;
        this.notificationService = notificationService;
    }

    @Override
    @Transactional
    public Torrent uploadTorrent(TorrentUploadRequest request, Long uploaderId) {
        System.out.println("=== 开始处理种子上传 ===");
        System.out.println("上传者ID: " + uploaderId);
        System.out.println("种子标题: " + request.getTitle());
        System.out.println("种子分类ID: " + request.getCategoryId());
        
        try {
            // 解析种子文件
            Map<String, Object> torrentInfo = parseTorrentFile(request.getFile());
            System.out.println("种子文件解析结果: " + torrentInfo);
            
            if (torrentInfo == null) {
                System.out.println("种子文件解析失败");
                throw new RuntimeException("无效的种子文件");
            }

            // 获取info_hash
            String infoHash = (String) torrentInfo.get("info_hash");
            if (infoHash == null) {
                System.out.println("无法获取info_hash");
                throw new RuntimeException("无法获取info_hash");
            }
            
            // 检查info_hash是否已存在
            Torrent existingTorrent = lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
            
            if (existingTorrent != null) {
                if (!existingTorrent.getIsDeleted()) {
                    // 种子存在且未删除
                    System.out.println("种子已存在且未删除，拒绝上传");
                    throw new RuntimeException("该种子已存在");
                } else {
                    // 种子已被删除，恢复并更新信息
                    System.out.println("发现已删除的种子，恢复并更新信息");
                    existingTorrent.setTitle(request.getTitle());
                    existingTorrent.setDescription(request.getDescription());
                    existingTorrent.setCategoryId(request.getCategoryId());
                    existingTorrent.setUploaderId(uploaderId);
                    existingTorrent.setStatus(TorrentConstant.STATUS_PENDING); // 待审核状态
                    existingTorrent.setPromotionStatus(0);
                    existingTorrent.setCreatedTime(LocalDateTime.now());
                    existingTorrent.setLastAction(LocalDateTime.now());
                    existingTorrent.setIsDeleted(false);
                    existingTorrent.setSeeders(0);
                    existingTorrent.setLeechers(0);
                    existingTorrent.setFinished(0);
                    
                    // 更新文件大小
                    Long fileSize = (Long) torrentInfo.get("total_size");
                    if (fileSize == null) {
                        fileSize = request.getFile().getSize();
                    }
                    existingTorrent.setFileSize(fileSize);
                    existingTorrent.setSize(fileSize);
                    
                    // 重新保存种子文件
                    try {
                        String filename = infoHash + ".torrent";
                        System.out.println("重新保存种子文件: " + filename);
                        FileUtil.saveTorrentFile(request.getFile(), TorrentConstant.TORRENT_SAVE_PATH, filename);
                        System.out.println("种子文件保存成功");
                    } catch (Exception e) {
                        System.out.println("保存种子文件失败: " + e.getMessage());
                        throw new RuntimeException("种子文件保存失败: " + e.getMessage());
                    }
                    
                    updateById(existingTorrent);
                    System.out.println("种子恢复成功，ID: " + existingTorrent.getId());
                    return existingTorrent;
                }
            }

            // 创建种子记录
            Torrent torrent = new Torrent();
            torrent.setTitle(request.getTitle());
            torrent.setInfoHash(infoHash);
            
            // 获取文件大小
            Long fileSize = (Long) torrentInfo.get("total_size");
            if (fileSize == null) {
                fileSize = request.getFile().getSize();
            }
            torrent.setFileSize(fileSize);
            torrent.setSize(fileSize);
            
            torrent.setCategoryId(request.getCategoryId());
            torrent.setCategory(getCategoryNameById(request.getCategoryId()));
            torrent.setDescription(request.getDescription());
            torrent.setUploaderId(uploaderId);
            torrent.setStatus(TorrentConstant.STATUS_PENDING);
            torrent.setPromotionStatus(0);
            torrent.setCreatedTime(LocalDateTime.now());
            torrent.setLastAction(LocalDateTime.now());
            torrent.setIsDeleted(false);
            torrent.setSeeders(0);
            torrent.setLeechers(0);
            torrent.setFinished(0);

            // 保存种子文件
            try {
                String filename = infoHash + ".torrent";
                System.out.println("保存种子文件: " + filename);
                FileUtil.saveTorrentFile(request.getFile(), TorrentConstant.TORRENT_SAVE_PATH, filename);
                System.out.println("种子文件保存成功");
            } catch (Exception e) {
                System.out.println("保存种子文件失败: " + e.getMessage());
                throw new RuntimeException("种子文件保存失败: " + e.getMessage());
            }
            
            // 保存到数据库
            System.out.println("保存种子到数据库");
            save(torrent);
            System.out.println("种子保存成功，ID: " + torrent.getId());

            // 发送种子上传通知
            try {
                notificationService.sendTorrentNotification(uploaderId, torrent.getTitle(), "上传成功，等待审核");
                System.out.println("种子上传通知发送成功");
            } catch (Exception e) {
                System.out.println("发送种子上传通知失败: " + e.getMessage());
            }

            return torrent;
        } catch (Exception e) {
            System.out.println("种子上传失败: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("种子上传失败: " + e.getMessage());
        }
    }

    @Override
    public byte[] downloadTorrent(Long torrentId, String passkey) {
        System.out.println("=== 种子下载被调用 ===");
        System.out.println("TorrentID: " + torrentId);
        System.out.println("Passkey: " + passkey);
        
        Torrent torrent = getById(torrentId);
        if (torrent == null || torrent.getIsDeleted()) {
            System.out.println("ERROR: 种子不存在或已删除");
            throw new RuntimeException("种子不存在");
        }
        
        System.out.println("种子信息: " + torrent.getTitle());
        System.out.println("InfoHash: " + torrent.getInfoHash());

        String filepath = TorrentConstant.TORRENT_SAVE_PATH + torrent.getInfoHash() + ".torrent";
        System.out.println("种子文件路径: " + filepath);
        
        byte[] torrentData = FileUtil.readFile(filepath);
        if (torrentData == null) {
            System.out.println("ERROR: 读取种子文件失败");
            throw new RuntimeException("读取种子文件失败");
        }
        
        System.out.println("成功读取种子文件，大小: " + torrentData.length);

        // 修改Tracker URL并保持private标志
        Map<String, Object> torrentMap = BencodeUtil.decodeTorrent(torrentData);
        if (torrentMap != null) {
            // 修改announce URL
            String announceUrl = "http://localhost:8080/api/announce?passkey=" + passkey;
            torrentMap.put("announce", announceUrl);
            
            // 确保info字典中的private标志保持不变
            Map<String, Object> info = (Map<String, Object>) torrentMap.get("info");
            if (info != null && !info.containsKey("private")) {
                // 如果原始种子没有private标志，添加它
                info.put("private", 1L);
            }
            
            // 重新编码种子文件
            return BencodeUtil.encodeTorrent(torrentMap);
        }
        
        return torrentData;
    }

    @Override
    public Map<String, Object> parseTorrentFile(MultipartFile file) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            byte[] fileBytes = file.getBytes();
            
            // 解析种子文件
            Map<String, Object> torrentMap = BencodeUtil.decodeTorrent(fileBytes);
            if (torrentMap == null) {
                System.out.println("解析种子文件失败: 无效的种子文件格式");
                result.put("total_size", (long) file.getSize());
                return result;
            }
            
            System.out.println("解析种子文件成功");
            
            // 尝试计算info_hash
            Map<String, Object> info = (Map<String, Object>) torrentMap.get("info");
            System.out.println("info字段存在: " + (info != null));
            System.out.println("info = " + info);
            
            if (info != null) {
                try {
                    // 尝试计算SHA1
                    byte[] infoData = BencodeUtil.encodeTorrent(info);
                    System.out.println("infoData= " + infoData);
                    if (infoData != null) {
                        // 使用Java内置的MessageDigest计算SHA1
                        java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-1");
                        byte[] hash = md.digest(infoData);
                        System.out.println("hash = " + hash);
                        String infoHash = bytesToHex(hash);
                        System.out.println("infoHash = " + infoHash);
                        result.put("info_hash", infoHash);
                        System.out.println("成功计算info_hash: " + infoHash);
                    }
                } catch (Exception e) {
                    System.out.println("计算info_hash失败: " + e.getMessage());
                    e.printStackTrace();
                }

                // 计算总大小
                Long length = (Long) info.get("length");
                if (length != null) {
                    result.put("total_size", length);
                    System.out.println("文件大小: " + length);
                } else {
                    // 如果是多文件种子
                    List<Map<String, Object>> files = (List<Map<String, Object>>) info.get("files");
                    if (files != null) {
                        long totalSize = 0;
                        for (Map<String, Object> fileInfo : files) {
                            Long fileLength = (Long) fileInfo.get("length");
                            if (fileLength != null) {
                                totalSize += fileLength;
                            }
                        }
                        result.put("total_size", totalSize);
                        System.out.println("总文件大小: " + totalSize);
                    }
                }

                // 保存private标志
                Long privateFlag = (Long) info.get("private");
                result.put("private", privateFlag != null && privateFlag == 1);
                System.out.println("Private标志: " + (privateFlag != null && privateFlag == 1));
            }
            
            return result;
        } catch (IOException e) {
            System.out.println("读取文件内容失败: " + e.getMessage());
            e.printStackTrace();
            result.put("total_size", (long) file.getSize());
            return result;
        } catch (Exception e) {
            System.out.println("解析种子文件失败: " + e.getMessage());
            e.printStackTrace();
            // 返回最基本的信息
            result.put("total_size", (long) file.getSize());
            return result;
        }
    }
    
    // 字节数组转十六进制字符串
    private String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

    @Override
    public void updateTorrentStatus(Long torrentId, Integer status) {
        lambdaUpdate()
            .eq(Torrent::getId, torrentId)
            .set(Torrent::getStatus, status)
            .update();
    }

    @Override
    public void updateSeedersAndLeechers(Long torrentId, int seeders, int leechers) {
        baseMapper.updatePeerCount(torrentId, seeders, leechers);
    }

    @Override
    public Page<Torrent> searchTorrents(String keyword, Integer categoryId, Integer promotionStatus, int page, int size) {
        return lambdaQuery()
            .like(keyword != null, Torrent::getTitle, keyword)
            .eq(categoryId != null, Torrent::getCategoryId, categoryId)
            .eq(promotionStatus != null, Torrent::getPromotionStatus, promotionStatus)
            .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
            .eq(Torrent::getIsDeleted, false)
            .orderByDesc(Torrent::getCreatedTime)
            .page(new Page<>(page, size));
    }

    @Override
    public boolean isValidInfoHash(String infoHash) {
        return lambdaQuery()
            .eq(Torrent::getInfoHash, infoHash)
            .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
            .eq(Torrent::getIsDeleted, false)
            .exists();
    }

    @Override
    public void incrementDownloadCount(Long torrentId) {
        baseMapper.incrementFinished(torrentId);
    }

    @Override
    public List<Torrent> getTorrentsByCategory(Integer categoryId) {
        return lambdaQuery()
            .eq(Torrent::getCategoryId, categoryId)
            .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
            .eq(Torrent::getIsDeleted, false)
            .list();
    }
    
    @Override
    @Transactional
    public void deleteTorrent(Long torrentId, Long userId) {
        System.out.println("=== 开始删除种子 ===");
        System.out.println("种子ID: " + torrentId);
        System.out.println("操作用户ID: " + userId);
        
        Torrent torrent = getById(torrentId);
        if (torrent == null || torrent.getIsDeleted()) {
            System.out.println("ERROR: 种子不存在或已删除");
            throw new RuntimeException("种子不存在");
        }
        
        System.out.println("种子信息: " + torrent.getTitle());
        System.out.println("种子上传者ID: " + torrent.getUploaderId());
        
        // 获取当前用户信息
        User currentUser = userService.getById(userId);
        if (currentUser == null) {
            System.out.println("ERROR: 用户不存在");
            throw new RuntimeException("用户不存在");
        }
        
        System.out.println("当前用户: " + currentUser.getUsername());
        System.out.println("用户等级: " + currentUser.getUserClass());
        
        // 检查删除权限：上传者或管理员可以删除种子
        boolean canDelete = false;
        
        // 1. 检查是否为上传者
        if (torrent.getUploaderId().equals(userId)) {
            System.out.println("用户是种子上传者，允许删除");
            canDelete = true;
        }
        
        // 2. 检查是否为管理员（用户等级4为管理员）
        if (currentUser.getUserClass() >= 4) {
            System.out.println("用户是管理员，允许删除");
            canDelete = true;
        }
        
        if (!canDelete) {
            System.out.println("ERROR: 用户无权删除该种子");
            throw new RuntimeException("没有权限删除该种子");
        }
        
        try {
            // 1. 删除种子文件
            String torrentFilePath = TorrentConstant.TORRENT_SAVE_PATH + torrent.getInfoHash() + ".torrent";
            System.out.println("删除种子文件: " + torrentFilePath);
            if (FileUtil.deleteFile(torrentFilePath)) {
                System.out.println("种子文件删除成功");
            } else {
                System.out.println("种子文件删除失败或文件不存在");
            }
            
            // 2. 删除相关的 peer 记录
            System.out.println("删除相关的 peer 记录");
            peerService.lambdaUpdate()
                .eq(Peer::getTorrentId, torrentId)
                .remove();
            
            // 3. 软删除种子记录
            System.out.println("执行软删除操作");
            lambdaUpdate()
                .eq(Torrent::getId, torrentId)
                .set(Torrent::getIsDeleted, true)
                .update();
            
            System.out.println("种子删除成功");
        } catch (Exception e) {
            System.out.println("ERROR: 删除种子过程中发生错误: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("删除种子失败: " + e.getMessage());
        }
    }
    
    @Override
    public Torrent getTorrent(Long torrentId) {
        return getById(torrentId);
    }
    
    @Override
    public Page<Torrent> listTorrents(String category, String keyword, Boolean promotionOnly, int page, int size) {
        LambdaQueryWrapper<Torrent> queryWrapper = new LambdaQueryWrapper<>();
        
        queryWrapper.eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
                   .eq(Torrent::getIsDeleted, false);
        
        if (category != null && !category.isEmpty()) {
            // 支持按分类名称或分类ID搜索
            try {
                Integer categoryId = getCategoryIdByName(category);
                if (categoryId != null) {
                    queryWrapper.eq(Torrent::getCategoryId, categoryId);
                } else {
                    // 如果不是预定义分类，按category字段搜索
                    queryWrapper.eq(Torrent::getCategory, category);
                }
            } catch (Exception e) {
                // 如果转换失败，按category字段搜索
                queryWrapper.eq(Torrent::getCategory, category);
            }
        }
        
        if (keyword != null && !keyword.isEmpty()) {
            queryWrapper.like(Torrent::getTitle, keyword);
        }
        
        if (promotionOnly != null && promotionOnly) {
            queryWrapper.gt(Torrent::getPromotionStatus, 0);
        }
        
        queryWrapper.orderByDesc(Torrent::getCreatedTime);
        
        return page(new Page<>(page, size), queryWrapper);
    }
    
    // 根据分类名称获取分类ID
    private Integer getCategoryIdByName(String categoryName) {
        if (categoryName == null || categoryName.trim().isEmpty()) {
            return null;
        }
        
        // 根据分类名称映射到ID
        switch (categoryName) {
            case "电影":
                return 1;
            case "电视剧":
                return 2;
            case "音乐":
                return 3;
            case "软件":
                return 4;
            case "游戏":
                return 5;
            case "电子书":
                return 6;
            case "动漫":
                return 7;
            case "其他":
                return 8;
            default:
                return null;
        }
    }
    
    // 根据分类ID获取分类名称
    private String getCategoryNameById(Integer categoryId) {
        if (categoryId == null) {
            return "其他";
        }
        
        switch (categoryId) {
            case 1:
                return "电影";
            case 2:
                return "电视剧";
            case 3:
                return "音乐";
            case 4:
                return "软件";
            case 5:
                return "游戏";
            case 6:
                return "电子书";
            case 7:
                return "动漫";
            case 8:
                return "其他";
            default:
                return "其他";
        }
    }
    
    @Override
    public Page<Torrent> getPendingTorrents(int page, int size) {
        System.out.println("=== TorrentService.getPendingTorrents ===");
        System.out.println("查询状态: " + TorrentConstant.STATUS_PENDING);
        
        Page<Torrent> result = lambdaQuery()
            .eq(Torrent::getStatus, TorrentConstant.STATUS_PENDING)
            .eq(Torrent::getIsDeleted, false)
            .orderByAsc(Torrent::getCreatedTime)
            .page(new Page<>(page, size));
            
        System.out.println("查询结果 - 总数: " + result.getTotal() + ", 当前页记录数: " + result.getRecords().size());
        
        return result;
    }
    
    @Override
    @Transactional
    public void approveTorrent(Long torrentId) {
        lambdaUpdate()
            .eq(Torrent::getId, torrentId)
            .set(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
            .update();
    }
    
    @Override
    @Transactional
    public void rejectTorrent(Long torrentId, String reason) {
        lambdaUpdate()
            .eq(Torrent::getId, torrentId)
            .set(Torrent::getStatus, TorrentConstant.STATUS_DISABLED)
            .set(Torrent::getRejectReason, reason)
            .update();
    }
    
    @Override
    @Transactional
    public void setPromotion(Long torrentId, Integer promotionType, Integer durationHours) {
        Torrent torrent = getById(torrentId);
        if (torrent == null || torrent.getIsDeleted()) {
            throw new RuntimeException("种子不存在");
        }
        
        LocalDateTime endTime = null;
        if (promotionType > 0 && durationHours > 0) {
            endTime = LocalDateTime.now().plusHours(durationHours);
        }
        
        Torrent updateTorrent = new Torrent();
        updateTorrent.setId(torrentId);
        updateTorrent.setPromotionStatus(promotionType);
        
        if (promotionType > 0) {
            updateTorrent.setPromotionStartTime(LocalDateTime.now());
            updateTorrent.setPromotionEndTime(endTime);
        } else {
            updateTorrent.setPromotionStartTime(null);
            updateTorrent.setPromotionEndTime(null);
        }
        
        updateById(updateTorrent);
    }
    
    @Override
    public Page<Torrent> getUserTorrents(Long userId, int page, int size) {
        return lambdaQuery()
            .eq(Torrent::getUploaderId, userId)
            .eq(Torrent::getIsDeleted, false)
            .orderByDesc(Torrent::getCreatedTime)
            .page(new Page<>(page, size));
    }
    
    @Override
    public String reportClientStatus(String infoHash, String passkey, Long uploaded, Long downloaded, Long left, String event) {
        try {
            // 验证infoHash
            if (!isValidInfoHash(infoHash)) {
                return "d14:failure reason13:invalid torrente";
            }
            
            // 获取用户信息（通过passkey）
            User user = userService.lambdaQuery()
                    .eq(User::getPasskey, passkey)
                    .eq(User::getStatus, 1)
                    .one();
            
            if (user == null) {
                return "d14:failure reason13:invalid passkeye";
            }
            
            // 更新peer信息
            peerService.updatePeerStatus(infoHash, user.getId(), "127.0.0.1", 6881, 
                                       uploaded, downloaded, left, event, "PT-Client");
            
            // 更新用户上传下载统计
            userService.updateUserStats(user.getId(), uploaded, downloaded);
            
            // 获取种子ID
            Torrent torrent = lambdaQuery().eq(Torrent::getInfoHash, infoHash).one();
            if (torrent != null) {
                // 更新种子做种和下载统计
                int seeders = peerService.countSeeders(infoHash);
                int leechers = peerService.countLeechers(infoHash);
                updateSeedersAndLeechers(torrent.getId(), seeders, leechers);
                
                // 返回peer列表
                List<Peer> peers = peerService.getPeers(infoHash, user.getId(), TorrentConstant.MAX_PEERS);
                byte[] peerResponse = BencodeUtil.encodePeerResponse(peers, seeders, leechers);
                return new String(peerResponse, StandardCharsets.ISO_8859_1);
            }
            
            // 简化实现，返回成功响应
            return "d8:intervali1800e8:completei0e10:incompletei0e5:peerslee";
        } catch (Exception e) {
            log.error("报告客户端状态失败", e);
            return "d14:failure reason13:internal errore";
        }
    }
    
    @Override
    public Torrent uploadTorrent(Torrent torrent, InputStream torrentFile, Long userId) {
        // 这个方法可以作为内部实现，实际调用上面的uploadTorrent(TorrentUploadRequest, Long)方法
        // 简化实现
        torrent.setUploaderId(userId);
        torrent.setCreatedTime(LocalDateTime.now());
        torrent.setStatus(TorrentConstant.STATUS_PENDING);
        torrent.setIsDeleted(false);
        
        save(torrent);
        
        return torrent;
    }

    /**
     * 自动促销管理 - 根据种子健康度和站点需求自动设置促销
     */
    @Transactional
    public void autoPromotionManagement() {
        System.out.println("=== 开始自动促销管理 ===");
        
        try {
            // 1. 清理过期的促销
            cleanExpiredPromotions();
            
            // 2. 为健康度低的种子设置促销
            promoteUnhealthyTorrents();
            
            // 3. 为新上传的种子设置新手促销
            promoteNewTorrents();
            
            // 4. 根据站点整体分享率情况调整促销策略
            adjustPromotionStrategy();
            
            System.out.println("=== 自动促销管理完成 ===");
        } catch (Exception e) {
            log.error("自动促销管理失败", e);
            System.out.println("ERROR: 自动促销管理失败: " + e.getMessage());
        }
    }
    
    /**
     * 清理过期的促销
     */
    private void cleanExpiredPromotions() {
        System.out.println("清理过期促销...");
        
        boolean success = lambdaUpdate()
                .gt(Torrent::getPromotionStatus, 0)
                .isNotNull(Torrent::getPromotionEndTime)
                .lt(Torrent::getPromotionEndTime, LocalDateTime.now())
                .set(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .set(Torrent::getPromotionEndTime, null)
                .set(Torrent::getPromotionStartTime, null)
                .update();
        
        // 查询实际更新的数量
        long count = lambdaQuery()
                .eq(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .isNull(Torrent::getPromotionEndTime)
                .count();
        
        System.out.println("清理了 " + count + " 个过期促销种子");
    }
    
    /**
     * 为健康度低的种子设置促销
     */
    private void promoteUnhealthyTorrents() {
        System.out.println("为健康度低的种子设置促销...");
        
        // 查找做种人数少于3的种子
        List<Torrent> unhealthyTorrents = lambdaQuery()
                .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
                .eq(Torrent::getIsDeleted, false)
                .eq(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .and(wrapper -> wrapper.isNull(Torrent::getSeeders).or().le(Torrent::getSeeders, 3))
                .gt(Torrent::getCreatedTime, LocalDateTime.now().minusDays(90)) // 只处理90天内的种子
                .list();
        
        for (Torrent torrent : unhealthyTorrents) {
            // 设置为免费下载+2倍上传，持续7天
            setPromotion(torrent.getId(), 
                        TorrentConstant.PROMOTION_2X_UPLOAD_HALF_DOWNLOAD, 
                        7 * 24);
        }
        
        System.out.println("为 " + unhealthyTorrents.size() + " 个健康度低的种子设置了促销");
    }
    
    /**
     * 为新上传的种子设置新手促销
     */
    private void promoteNewTorrents() {
        System.out.println("为新种子设置促销...");
        
        // 查找24小时内新上传的种子
        List<Torrent> newTorrents = lambdaQuery()
                .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
                .eq(Torrent::getIsDeleted, false)
                .eq(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .gt(Torrent::getCreatedTime, LocalDateTime.now().minusDays(1))
                .list();
        
        for (Torrent torrent : newTorrents) {
            // 设置为2倍上传，持续3天
            setPromotion(torrent.getId(), 
                        TorrentConstant.PROMOTION_2X_UPLOAD, 
                        3 * 24);
        }
        
        System.out.println("为 " + newTorrents.size() + " 个新种子设置了促销");
    }
    
    /**
     * 根据站点整体分享率情况调整促销策略
     */
    private void adjustPromotionStrategy() {
        System.out.println("调整全站促销策略...");
        
        // 计算站点整体分享率
        double siteAverageRatio = calculateSiteAverageShareRatio();
        System.out.println("站点平均分享率: " + siteAverageRatio);
        
        if (siteAverageRatio < 0.8) {
            // 分享率偏低，增加免费下载种子
            promoteRandomTorrentsForFreeDownload();
        } else if (siteAverageRatio > 2.0) {
            // 分享率很高，可以减少一些促销
            reduceExcessivePromotions();
        }
    }
    
    /**
     * 计算站点平均分享率
     */
    private double calculateSiteAverageShareRatio() {
        // 这里应该从数据库统计所有用户的分享率
        // 简化实现：使用mapper查询
        List<User> users = userService.lambdaQuery()
                .eq(User::getStatus, 1) // 正常用户
                .gt(User::getDownloaded, 0) // 有下载记录的用户
                .list();
        
        if (users.isEmpty()) {
            return 1.0;
        }
        
        double totalRatio = users.stream()
                .mapToDouble(User::getShareRatio)
                .sum();
        
        return totalRatio / users.size();
    }
    
    /**
     * 随机选择种子设置免费下载
     */
    private void promoteRandomTorrentsForFreeDownload() {
        System.out.println("为改善站点分享率，设置随机免费下载种子...");
        
        List<Torrent> candidates = lambdaQuery()
                .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
                .eq(Torrent::getIsDeleted, false)
                .eq(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .ge(Torrent::getSeeders, 5) // 有足够做种人的种子
                .orderByDesc(Torrent::getCreatedTime)
                .last("LIMIT 20") // 随机选择20个
                .list();
        
        for (Torrent torrent : candidates) {
            setPromotion(torrent.getId(), 
                        TorrentConstant.PROMOTION_FREE, 
                        24); // 免费24小时
        }
        
        System.out.println("设置了 " + candidates.size() + " 个种子为免费下载");
    }
    
    /**
     * 减少过度的促销
     */
    private void reduceExcessivePromotions() {
        System.out.println("站点分享率较高，减少部分促销...");
        
        // 取消一些2倍上传的促销，保留免费下载
        boolean success = lambdaUpdate()
                .eq(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_2X_UPLOAD)
                .set(Torrent::getPromotionStatus, TorrentConstant.PROMOTION_NORMAL)
                .set(Torrent::getPromotionEndTime, null)
                .set(Torrent::getPromotionStartTime, null)
                .last("LIMIT 10") // 只取消10个
                .update();
        
        System.out.println("取消2倍上传促销" + (success ? "成功" : "失败"));
    }
    
    /**
     * 获取促销统计信息
     */
    public Map<String, Object> getPromotionStats() {
        Map<String, Object> stats = new HashMap<>();
        
        // 各类促销种子数量
        stats.put("freeDownloads", countByPromotionType(TorrentConstant.PROMOTION_FREE));
        stats.put("doubleUploads", countByPromotionType(TorrentConstant.PROMOTION_2X_UPLOAD));
        stats.put("halfDownloads", countByPromotionType(TorrentConstant.PROMOTION_HALF_DOWNLOAD));
        stats.put("comboPromotions", countByPromotionType(TorrentConstant.PROMOTION_2X_UPLOAD_HALF_DOWNLOAD));
        
        // 即将过期的促销
        long expiringSoon = lambdaQuery()
                .gt(Torrent::getPromotionStatus, 0)
                .isNotNull(Torrent::getPromotionEndTime)
                .between(Torrent::getPromotionEndTime, 
                        LocalDateTime.now(), 
                        LocalDateTime.now().plusHours(24))
                .count();
        stats.put("expiringSoon", expiringSoon);
        
        return stats;
    }
    
    private long countByPromotionType(int promotionType) {
        return lambdaQuery()
                .eq(Torrent::getPromotionStatus, promotionType)
                .eq(Torrent::getStatus, TorrentConstant.STATUS_NORMAL)
                .eq(Torrent::getIsDeleted, false)
                .count();
    }

    @Override
    @Transactional
    public void updateTorrentStats(Long torrentId) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 设置超时时间为2小时
        LocalDateTime timeout = now.minusHours(2);
        
        // 统计做种者数量（seeder=true且last_action在超时时间内）
        Integer seeders = peerService.lambdaQuery()
                .eq(Peer::getTorrentId, torrentId)
                .eq(Peer::getSeeder, true)
                .gt(Peer::getLastAction, timeout)
                .count()
                .intValue();
        
        // 统计下载者数量（seeder=false且last_action在超时时间内）
        Integer leechers = peerService.lambdaQuery()
                .eq(Peer::getTorrentId, torrentId)
                .eq(Peer::getSeeder, false)
                .gt(Peer::getLastAction, timeout)
                .count()
                .intValue();
        
        // 更新种子统计信息
        Torrent torrent = getById(torrentId);
        if (torrent != null) {
            torrent.setSeeders(seeders);
            torrent.setLeechers(leechers);
            torrent.setLastAction(now);
            updateById(torrent);
            log.info("更新种子统计信息 - torrentId: {}, seeders: {}, leechers: {}", 
                torrentId, seeders, leechers);
        }
    }

    @Override
    public boolean checkTorrentExists(String infoHash) {
        return lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .eq(Torrent::getStatus, 1)
                .eq(Torrent::getIsDeleted, false)
                .exists();
    }
} 